/*
 * @Author: NingJian
 * @Date: 2021-08-24 16:27:18
 * @LastEditTime: 2021-09-14 17:49:59
 * @LastEditors: NingJian
 * @Description: 
 * @FilePath: /musesdk/src/utils/utils.cpp
 * 
 */
#ifndef OS_LINUX
#include <filesystem>
namespace fs = std::filesystem;
#else
#include <experimental/filesystem>
namespace fs = std::experimental::filesystem;
#endif
#include <iostream>
#include <fstream>
#include "../pcie/pcie.h"
#include "utils.h"

int write_pcie_file(CPcieComm &cpc, fs::path &file, int start_addr)
{ 
    if (!fs::exists(file)) return 0;
    auto len = fs::file_size(file);
    if (len > 0)
    {
        std::ifstream infile;
        infile.open(file.string(), std::ios::binary | std::ios::in);
        if (infile.is_open())
        {
            uint8_t *mem = new uint8_t[len];
            infile.read((char *)mem, len);
            cpc.pcie_write(start_addr, mem, len);
            delete [] mem;
            return len;
        }
    }
    return 0;
}

void write_signle_model(CPcieComm &cpc, fs::path &mp, int start_layer, ModelInfo &mi)
{
    int base_addr = 0;
    for (int i = 1; i <= mi.layers_numbers; i++)
    {
        std::string file_name = std::string("insts/layer") + std::to_string(i) + "_inst.bin";
        auto ints_p = mp;
        ints_p.append(file_name);
        base_addr += write_pcie_file(cpc, ints_p, base_addr);
    }
    for (int i = 1; i <= mi.layers_numbers; i++)
    {
        std::string file_name = std::string("datas/layer") + std::to_string(i) + "_data.bin";
        auto ints_p = mp;
        ints_p.append(file_name);
        base_addr += write_pcie_file(cpc, ints_p, base_addr);
    }
    {
        // load 1th layer act file to mem
        std::string file_name = std::string("inout/layer1_input_act0_file.bin");
        auto ints_p = mp;
        ints_p.append(file_name);
        base_addr += write_pcie_file(cpc, ints_p, base_addr);
    }
    {
        // load last th layer out file to mem
        std::string file_name = std::string("inout/layer") + std::to_string(mi.layers_numbers) + "_output_file.bin";
        auto ints_p = mp;
        ints_p.append(file_name);
        base_addr += write_pcie_file(cpc, ints_p, base_addr);
    }
    // load all layer act file to mem
    for (int i = 1; i <= mi.layers_numbers; i++)
    {
        std::string file_name = std::string("inout/layer") + std::to_string(i) + "_output_file.bin";
        auto ints_p = mp;
        ints_p.append(file_name);
        base_addr += write_pcie_file(cpc, ints_p, base_addr);
    }
}

void write_full_model(CPcieComm &cpc, fs::path &mp, ModelInfo &mi)
{
    int base_addr = 0;
    for (int i = 1; i <= mi.layers_numbers; i++)
    {
        std::string file_name = std::string("insts/layer") + std::to_string(i) + "_inst.bin";
        auto ints_p = mp;
        ints_p.append(file_name);
        base_addr += write_pcie_file(cpc, ints_p, base_addr);
    }
    for (int i = 1; i <= mi.layers_numbers; i++)
    {
        std::string file_name = std::string("datas/layer") + std::to_string(i) + "_data.bin";
        auto ints_p = mp;
        ints_p.append(file_name);
        base_addr += write_pcie_file(cpc, ints_p, base_addr);
    }
    {
        // load 1th layer act file to mem
        std::string file_name = std::string("inout/layer1_input_act0_file.bin");
        auto ints_p = mp;
        ints_p.append(file_name);
        mi.input_address = base_addr;
        mi.input_size = write_pcie_file(cpc, ints_p, base_addr);
        mi.output_address = mi.input_address + mi.input_size;
    }
    {
        // load last th layer out file to mem
        std::string file_name = std::string("inout/layer") + std::to_string(mi.layers_numbers) + "_output_file.bin";
        auto ints_p = mp;
        ints_p.append(file_name);
        mi.output_size = fs::file_size(ints_p);
    }
}